package controller

//路由解析后来到这里进行进一步的处理
import (
	"encoding/json"
	"fmt"
	"gin_wuwen_back/dao"
	"gin_wuwen_back/model"
	"gin_wuwen_back/param"
	"gin_wuwen_back/service"
	"gin_wuwen_back/tool"
	"github.com/dgrijalva/jwt-go"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func (tmp *RouterControl) hello(context *gin.Context) { //作为类的一个方法

}
func (tmp *RouterControl) Sendsmscode(context *gin.Context) { //作为路由管理类的一种方法
	//发送验证码
	//这里我们假设我们要发送验证码的接口为
	//http://127.0.0.1/api/sendcode?phone=17667425136 (GET)
	//首先我们先获取请求的数据phone
	phone, exist := context.GetQuery("phone")
	if !exist {
		context.JSON(200, map[string]interface{}{
			"code": 0,
			"msg":  "参数解析失败",
		})
		return
	}
	//真正要调用短信发送功能了,但我们在做一层封装
	Sevice := service.Service_func{} //实例化具体处理逻辑对象

	Issend := Sevice.SendCode(phone) //调用对象的方法来实现具体的功能
	if Issend {                      //发送成功，返回发送成功的json
		tool.Success(context, "发送成功")

		return
	}
	//发送失败返回发送失败的信息
	tool.Faild(context, "发送失败")

}

func (tmp *RouterControl) LoginSms(context *gin.Context) {
	//手机+验证码登陆的真正的处理函数
	var LoginSms param.LoginSmsParam
	err := tool.Decode(context.Request.Body, &LoginSms) //将我们需要传递的参数，
	// 以及对应参数的解析规则传入,如果验证成功那么他就自动将解析规则的结构体赋值填满
	if err != nil {
		tool.Faild(context, "参数解析失败")

		return

	}
	//完成手机号加验证码登陆
	US := service.Service_func{} //我们又将这几个方法全部封装在了server层
	member := US.SmsLogin(LoginSms)

	if member != nil {
		//用户的信息我们保存到session中，只要登录上我们就保存下用户的信息
		sess, _ := json.Marshal(member) //将这个结构体序列化为json的格式，
		// 后面的member其实在返回的时候已经进行了json的序列化
		err = tool.SetSess(context, "user_"+string(member.Id), sess)
		if err != nil {
			log.Println(err.Error())
			return
		}
		//用户登录成功之后我们进行设置一下cookie
		context.SetCookie("cookie_user", strconv.Itoa(int(member.Id)), 10*60, "/", "localohost", true, true)
		tool.Success(context, member) //如果成功我们就将解析出来的对象返回回去

	}
	tool.Faild(context, "登陆失败")

}

func (tmp *RouterControl) Captcha(context *gin.Context) {
	/*
	  @Description:用户登陆时生成图形验证码的逻辑,生成验证码并返回客户端
	  @receiver tmp 对象的参数
	  @param context 传过来的gin引擎，至关重要

	*/

	/*
	   @Description:生成图形验证码在tool中进行封装
	   @param context 传入gin引擎
	*/
	tool.GenerateCaptchaHandele(context) //生成验证码

}

func (tmp *RouterControl) VaCaptcha(context *gin.Context) {
	/*
	  @Description:验证验证码是否正确
	  @receiver tmp
	  @param context 上下文环境
	*/
	var captcha param.CaptchaResult
	err := tool.Decode(context.Request.Body, captcha)
	if err != nil {
		log.Println(err.Error())
		tool.Faild(context, "参数解析失败")
	}

	result := tool.VertifyCaptcha(captcha.Id, captcha.VertifyValue) //验证验证码
	if result {
		fmt.Println("验证成功")
	} else {
		fmt.Println("验证失败")
	}

}

/*
  @Description: 用用户名和密码来进行登陆
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) LoginByPassword(context *gin.Context) {
	//解析用户传递过来的信息
	var LoginData param.LoginByPass
	err := tool.Decode(context.Request.Body, &LoginData)
	if err != nil {
		log.Println(err.Error())

	}
	//验证验证码
	vaild := tool.VertifyCaptcha(LoginData.Id, LoginData.Value)
	if !vaild {
		tool.Faild(context, "验证码不正确,请重新验证")
		return
	}
	//登陆
	ms := service.Service_func{}
	member, err1 := ms.LoginBypass(LoginData.Name, LoginData.Password)
	if err1 == nil {
		//用户的信息我们保存到session中，只要登录上我们就保存下用户的信息
		sess, _ := json.Marshal(member) //将这个结构体序列化为json的格式，并将其全部的内容全部存入到redis的数据库中
		// 后面的member其实在返回的时候已经进行了json的序列化
		err = tool.SetSess(context, "user_"+string(member.Id), sess)
		if err != nil {
			log.Println(err.Error())
			return

		}
		tmp.generateToken(context, member) //生成了token我们将token和一些必要信息返回
		//tool.Success(context, member)
		return
	}
	tool.Faild(context, "登陆失败")
	return

}

/*
  @Description: 用户使用用户名和密码，注册的接口
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) RegisterByPassword(context *gin.Context) {
	var RegisterParame param.RegisterParame
	err := tool.Decode(context.Request.Body, &RegisterParame)
	if err != nil {
		log.Println(err.Error())
		tool.Faild(context, "注册失败")
		return

	}
	//用要注册用户名来做一下搜索看用户是否注册过,如果注册过返回错误信息
	Func := new(service.Service_func)
	err = Func.Padlogin(&RegisterParame)
	if err != nil {
		log.Println(err.Error())
		if err.Error() == "用户已存在" {
			tool.Faild(context, "用户名已经注册")
			return
		}
		tool.Faild(context, "注册失败")
		return

	}

	//用户没有注册过，我们直接进行创建用户
	md := dao.Memberdao{tool.Dbengin}
	user := model.Member{}
	user.UserName = RegisterParame.Username
	user.Password = tool.EncoderSha256(RegisterParame.Password)
	user.Mobile = RegisterParame.Tele
	user.RegisterTime = time.Now().Unix()
	result := md.InsetMember(user)
	user.Id = result
	tool.Success(context, "注册成功")

}

/*
  @Description: 上传用户头像的处理函数
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) UploadAvator(context *gin.Context) {
	//1.解析上传的参数，肯定会有一个file文件以及用户的user_id来负责一下区分
	userId := context.PostForm("user_id") //用户id
	fmt.Println(userId)
	file, err := context.FormFile("avator")
	if err != nil || userId == "" {
		tool.Faild(context, "参数解析失败")
		return
	}

	//2.判断user_id所对应的用户是否已经登陆了，这里我们可能就要引入session的概念了
	sess := tool.GetSess(context, "user_"+userId)
	if sess == nil {
		tool.Faild(context, "参数不合法，解析失败")
		return
	}
	var memeber model.Member
	json.Unmarshal(sess.([]byte), &memeber) //在这memeber就被实例赋值了，获取了该对象的所有信息
	//登陆之后将一些字段保存到session中，便可以验证该用户是否登陆
	//3.file保存到本地
	fileName := "./static/img/" + strconv.FormatInt(time.Now().Unix(), 10) + file.Filename
	err = context.SaveUploadedFile(file, fileName)
	if err != nil {
		tool.Faild(context, "头像更新失败")
		return

	}
	//4.将保存下来的文件路径保存到用户表的用户图像字段中
	MemberServer := service.Service_func{}
	path := MemberServer.UploadAvator(memeber.Id, fileName[1:])
	if path != "" {
		tool.Success(context, "上传成功")

	}
	//

}

/*
  @Description:获取商品信息的接口
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) FoodCategory(context *gin.Context) {
	//接下来就是调用server层
	FoodCateServer := service.FoodCateServer{}
	FoodCateies, err := FoodCateServer.FoodCateServerFunc()
	if err != nil {
		tool.Faild(context, "查询失败")
	}
	tool.Success(context, FoodCateies)

}

/*
  @Description: 获取商户的信息，我们是根据经纬度来进行搜寻的
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) ShopViews(context *gin.Context) {
	//我们我们提供的Get请求的参数来获得我们将要查询的经纬度
	longitude := context.Query("longitude")
	latitude := context.Query("latitude")
	if longitude == "" || longitude == "undefined" || latitude == "" || latitude == "undefined" {
		longitude = "163.34"
		latitude = "48.34"

	}
	//将参数获得了以后，我们就要转入我们server层的编写
	shopeserver := service.ShopeServer{}
	shops := shopeserver.ShopList(longitude, latitude) //我们查询的是一个范围的，所以返回的是一个列表
	if len(shops) == 0 {
		tool.Faild(context, "未查询到信息")
		return
	}

	tool.Success(context, shops)

}

/*
  @Description:搜寻商家的信息，根据关键字
  @receiver tmp 我们来定义方法的路由对象
  @param context
*/
func (tmp *RouterControl) SearchShop(context *gin.Context) {
	longitude := context.Query("longitude")
	latitude := context.Query("latitude")
	keyword := context.Query("keyword")

	if keyword == "" {
		tool.Faild(context, "查询失败，请重新输入商户信息")
		return

	}
	if longitude == "" || longitude == "undefined" || latitude == "" || latitude == "undefined" {
		longitude = "163.34"
		latitude = "48.34"

	}
	//如果我们直到keyword不为空那么我们就执行真实的搜索
	shopsever := service.ShopeServer{}
	shops := shopsever.SearchShop(longitude, latitude, keyword)
	if len(shops) != 0 {
		tool.Success(context, shops)
	}
	tool.Faild(context, "查询失败")

}

/*
  @Description: //用户登陆后来进行查询自己的用户信息
  @receiver tmp
  @param context
*/
func (tmp *RouterControl) Userinfo(context *gin.Context) {
	claims := context.MustGet("claims").(*tool.CustomClaims)
	if claims == nil {
		tool.Faild(context, "失败了")
		return

	}
	//cookie, err := tool.CookieAuth(context)
	//if err != nil {
	//	context.Abort()
	//	tool.Faild(context, "还未登录，请登录后在进行操作")
	//	return
	//}
	//server层我们就定义一个方法，来获得我们需要的信息
	memberService := service.Service_func{}
	member := memberService.GetUserinfo(strconv.FormatInt(claims.ID, 10))
	if member != nil {
		//返回成功的信息给客户端
		tool.Success(context, member) //或者将其写开去掉password
		return

	}
	tool.Faild(context, "获取用户信息失败")
	return

}

/*
  @Description:token生成器
  @receiver tmp
  @param c 上下文
  @param user 查询出来的登陆信息正确的用户
*/
func (tmp *RouterControl) generateToken(c *gin.Context, user *model.Member) {
	// 构造SignKey: 签名和解签名需要使用一个值
	j := tool.NewJWT()

	// 构造用户claims信息(负荷)
	claims := tool.CustomClaims{
		user.Id,
		user.UserName,
		jwt.StandardClaims{
			NotBefore: int64(time.Now().Unix() - 1000), // 签名生效时间
			ExpiresAt: int64(time.Now().Unix() + 3600), // 签名过期时间
			Issuer:    "bgbiao.top",                    // 签名颁发者
		},
	}

	// 根据claims生成token对象
	token, err := j.CreateToken(claims)

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": -1,
			"msg":    err.Error(),
			"data":   nil,
		})
	}

	log.Println(token)
	// 封装一个响应数据,返回用户名和token
	type LoginResult struct {
		Name  string
		Token string
	}
	data := LoginResult{
		Name:  user.UserName,
		Token: token,
	}

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "登陆成功",
		"data":   data,
	})
	return

}

/*
  @Description: 获取post请求的参数，并存到redis数据库中，并保持实时的更新
*/
func (tmp *RouterControl) Message(c *gin.Context) {
	MessageData := param.MessageParame{}
	err := tool.Decode(c.Request.Body, &MessageData)
	if err != nil {
		log.Println(err.Error())
		return

	}
	redisclient := tool.InitRedisHome()
	data := redisclient.Get("1", false)
	data = data + MessageData.Message
	redisclient.Set("1", data)
	c.JSON(http.StatusOK, gin.H{
		"code":    1,
		"data":    "数据保存成功",
		"message": "success",
	})
	return

}

/*
  @Description: 获取信息
  @receiver tmp
  @param c
*/
func (tmp *RouterControl) GetMessage(c *gin.Context) {
	redisclient := tool.InitRedisHome()
	data := redisclient.Get("1", false)
	if len(data) != 0 {
		c.JSON(http.StatusOK, gin.H{
			"code":    1,
			"message": data,
		})
		return

	}
	c.JSON(http.StatusInternalServerError, gin.H{
		"code":    0,
		"message": "目前值为空，请稍后再试",
	})

}

/*
  @Description: 清空当前redis数据库当中的数据，为下一次识别做好准备
  @receiver tmp
  @param c
*/
func (tmp *RouterControl) DeleMessage(c *gin.Context) {
	redisclient := tool.InitRedisHome()
	redisclient.Dele("1")
	c.JSON(http.StatusOK, gin.H{
		"code":    1,
		"data":    "数据清除成功，可以开始了",
		"message": "success",
	})
	return

}

func (tmp *RouterControl) GetUrl(c *gin.Context) {
	PostData := param.GetvideoParame{}
	err := tool.Decode(c.Request.Body, &PostData)
	if err != nil {
		log.Println(err.Error())
		return
	}
	UrlDao := dao.NewVideoDao()

	UrlObject := UrlDao.GetUrl(PostData.Message)
	data := make(map[string]string)
	data["name"] = UrlObject.Vname
	data["url"] = UrlObject.Url
	if UrlObject != nil {
		c.JSON(http.StatusOK, gin.H{
			"code":    1,
			"data":    data,
			"message": "success",
		})
		return

	}

	c.JSON(http.StatusInternalServerError, gin.H{
		"code":    0,
		"data":    "出现错误，查询不到",
		"message": "faile",
	})
	return

}

/*
  @Description:这个函数中我们要做的就是
将从实时识别端反馈回来的不为空的数据我们存入redis数据库当中，做一个实时的更新
  @param msg
*/
func SetMqttMessage(msg mqtt.Message) {

	if string(msg.Payload()) == "" {
		log.Println("数据为空暂不记录")
		return

	}
	//开始数据的存储
	redisclient := tool.InitRedisHome()
	data := redisclient.Get("1", false)
	a := strings.HasSuffix(data, string(msg.Payload()))
	if a {
		log.Println("最后的字符串重复，不保存")
		return
	}
	data = data + "#" + string(msg.Payload())
	redisclient.Set("1", data)
	//c.JSON(http.StatusOK, gin.H{
	//	"code":    1,
	//	"data":    "数据保存成功",
	//	"message": "success",
	//})
	log.Println(data)
	log.Println("数据保存成功")
	return

}
